package impl.core;

import impl.gui.ChoiceInformationPanel;
import impl.gui.UBoxPanel;
import impl.gui.UDecideGUI;
import impl.parser.UDecideParser;
import impl.reasoning.UDecideReasoner;
import impl.reasoning.UDecideReasonerFactory;
import impl.reasoning.UDecideReasonerFactory.UDecideReasonerType;
import impl.util.UtilityAssertion;
import interfaces.abstracts.AbstractUDecideManager;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

import org.protege.editor.owl.OWLEditorKit;
import org.protege.editor.owl.model.OWLWorkspace;
import org.semanticweb.owlapi.expression.OWLEntityChecker;
import org.semanticweb.owlapi.expression.ShortFormEntityChecker;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.util.BidirectionalShortFormProviderAdapter;
import org.semanticweb.owlapi.util.SimpleShortFormProvider;

import exceptions.UDecideReasonerConnectionException;
import exceptions.UDecideReasonerRuntimeException;

public class UDecideManager extends AbstractUDecideManager {

	private static UDecideManager		instance;

	private OWLOntology					knowledgeBase;
	private OWLOntologyManager			owlOntologyManager;
	private OWLDataFactory				owlDataFactory;
	private OWLEditorKit				owlEditorKit;
	private OWLWorkspace				owlWorkspace;

	private OWLClassExpression			choiceClassExpression;

	private UDecideGUI					gui;
	private UBox						uBox;
	private UDecideReasoner				reasoner;
	private UDecideParser				parser;

	private LinkedList<Object>			disposableObjects	= new LinkedList<Object>();

	// Settings
	public static UDecideReasonerType	reasonerType		= UDecideReasonerType.KONCLUDE;
	public static boolean				fastKoncludeMode	= true;

	public UDecideManager(OWLOntology knowledgeBase, OWLOntologyManager owlOntologyManager, OWLDataFactory owlDataFactory, OWLEditorKit owlEditorKit,
			OWLWorkspace owlWorkspace) {
		UDecideManager.instance = this;
		this.knowledgeBase = knowledgeBase;
		this.owlOntologyManager = owlOntologyManager;
		this.owlDataFactory = owlDataFactory;
		this.owlEditorKit = owlEditorKit;
		this.owlWorkspace = owlWorkspace;

		this.uBox = new UBox();
		this.gui = new UDecideGUI();
		this.uBox.addUBoxChangeListener(this.gui);
	}

	public static UDecideManager getInstance() {
		return instance;
	}

	@Override
	public OWLOntology getKnowledgeBase() {
		return this.knowledgeBase;
	}

	@Override
	public OWLEntityChecker getOWLEntityChecker() {
		Set<OWLOntology> ontSet = new HashSet<OWLOntology>();
		ontSet.add(this.knowledgeBase);
		BidirectionalShortFormProviderAdapter bidiShortFormProvider = new BidirectionalShortFormProviderAdapter(this.owlOntologyManager, ontSet,
				new SimpleShortFormProvider());

		return new ShortFormEntityChecker(bidiShortFormProvider);
	}

	@Override
	public OWLOntologyManager getOwlOntologyManager() {
		return this.owlOntologyManager;
	}

	@Override
	public OWLDataFactory getOWLlDataFactory() {
		return this.owlDataFactory;
	}

	@Override
	public OWLEditorKit getOWLEditorKit() {
		return this.owlEditorKit;
	}

	@Override
	public OWLClassExpression getChoiceClassExpression() {
		return this.choiceClassExpression;
	}

	@Override
	public void setChoiceClassExpression(OWLClassExpression choiceClassExpression) {
		this.choiceClassExpression = choiceClassExpression;

		UBoxPanel.enableComputation(true);
	}

	/**
	 * Returns the instance of the current UDecideReasoner. If none could be instantiated by the factory, null is returned.
	 */
	@Override
	public UDecideReasoner getUDecideReasoner() {
		return this.reasoner;
	}

	@Override
	public UDecideParser getUDecideParser() {
		if (this.parser == null) {
			this.parser = new UDecideParser();
		}
		return this.parser;
	}

	@Override
	public void addUtilityAssertion(UtilityAssertion uAssertion) {
		this.uBox.addUtilityAssertion(uAssertion);
	}

	@Override
	public void clearUBox() {
		this.uBox.clear();
	}

	public UDecideGUI getGUI() {
		return this.gui;
	}

	public void prepareReasoner() throws UDecideReasonerConnectionException, UDecideReasonerRuntimeException {
		this.reasoner = UDecideReasonerFactory.getUDecideReasoner(this.knowledgeBase, this.choiceClassExpression, this.uBox.getUtilityAssertions(),
				UDecideManager.reasonerType);
		this.reasoner.calculateChoiceResults();
	}

	public OWLWorkspace getOwlWorkspace() {
		return this.owlWorkspace;
	}

	@Override
	public void removeUtilityAssertions(Collection<UtilityAssertion> uAssertions) {
		this.uBox.removeUtilityAssertions(uAssertions);
	}

	public UBox getUBox() {
		return this.uBox;
	}

	public void setUBox(UBox uBox) {
		this.uBox = uBox; // TODO: Change behaviour
	}

	@Override
	public void loadUBoxFromUtilityAssertions(Collection<UtilityAssertion> utilityAssertions) {
		this.uBox.loadUBoxFromUtilityAssertions(utilityAssertions);
	}

	@Override
	public void editUtilityAssertion(UtilityAssertion oldUtilityAssertion, UtilityAssertion newUtilityAssertion) {
		this.uBox.editUtilityAssertion(oldUtilityAssertion, newUtilityAssertion);
	}

	public void addDisposableObject(Object o) {
		this.disposableObjects.add(o);
	}

	public void close() {
		for (Object o : this.disposableObjects) {
			if (o instanceof ChoiceInformationPanel) {
				((ChoiceInformationPanel) o).dispose();
			}
		}
	}
}
